﻿// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Roslynator.CSharp.Refactorings;

internal static class ExpressionStatementRefactoring
{
    public static async Task ComputeRefactoringsAsync(RefactoringContext context, ExpressionStatementSyntax expressionStatement)
    {
        if (context.IsRefactoringEnabled(RefactoringDescriptors.IntroduceLocalVariable))
        {
            ExpressionSyntax expression = expressionStatement.Expression;

            if (expression?.IsMissing == false
                && context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(expression)
                && !expressionStatement.IsEmbedded()
                && expression is not AssignmentExpressionSyntax
                && !CSharpFacts.IsIncrementOrDecrementExpression(expression.Kind()))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() == false)
                {
                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                    if (typeSymbol?.IsErrorType() == false
                        && !typeSymbol.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)
                        && !typeSymbol.IsVoid())
                    {
                        var addAwait = false;

                        if (typeSymbol.OriginalDefinition.EqualsOrInheritsFromTaskOfT())
                        {
                            ISymbol enclosingSymbol = semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken);

                            addAwait = enclosingSymbol.IsAsyncMethod();
                        }

                        context.RegisterRefactoring(
                            IntroduceLocalVariableRefactoring.GetTitle(expression),
                            ct => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, ct),
                            RefactoringDescriptors.IntroduceLocalVariable);
                    }
                }
            }
        }
    }
}
